home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / ftpcli.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  35KB  |  1,518 lines

  1. /* Internet FTP client (interactive user)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. /* Mods by G1EMM and PA0GRI */
  5. /* modifications for encrypted password by ik1che 900419 */
  6. /* added "resume" and "rput" commands for interrupted file transfers
  7.  * by iw0cnb 15 Feb 92 */
  8.  
  9.  /* VIEW command added by Simon G1FHY. Mod by Paul@wolf.demon.co.uk */
  10. #include <stdio.h>
  11. #ifdef MSDOS
  12. #include <dir.h>
  13. #endif
  14. #ifdef UNIX
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #endif
  18. #include "global.h"
  19. #include "config.h"
  20. #include "mbuf.h"
  21. #include "session.h"
  22. #include "cmdparse.h"
  23. #include "proc.h"
  24. #include "tty.h"
  25. #include "socket.h"
  26. #include "ftp.h"
  27. #include "ftpcli.h"
  28. #include "commands.h"
  29. #include "netuser.h"
  30. #include "dirutil.h"
  31. #include "files.h"
  32. #include "config.h"
  33.  
  34. #define DIRBUF  256
  35.  
  36. #ifdef ALLSESSIONS
  37.  
  38. static int doascii __ARGS((int argc,char *argv[],void *p));
  39. static int dobatch __ARGS((int argc,char *argv[],void *p));
  40. static int dobinary __ARGS((int argc,char *argv[],void *p));
  41. static int doftpcd __ARGS((int argc,char *argv[],void *p));
  42. static int doftphelp __ARGS((int argc,char *argv[],void *p));
  43. static int doget __ARGS((int argc,char *argv[],void *p));
  44. static int dohash __ARGS((int argc,char *argv[],void *p));
  45. static int doverbose __ARGS((int argc,char *argv[],void *p));
  46. static int dolist __ARGS((int argc,char *argv[],void *p));
  47. static int dols __ARGS((int argc,char *argv[],void *p));
  48. static int doldir  __ARGS((int argc,char *argv[],void *p));
  49. static int dolcd  __ARGS((int argc,char *argv[],void *p));
  50. static int dolmkdir __ARGS((int argc,char *argv[],void *p));
  51. static int domkdir __ARGS((int argc,char *argv[],void *p));
  52. static int domget __ARGS((int argc,char *argv[],void *p));
  53. static int domput __ARGS((int argc,char *argv[],void *p));
  54. static int doput __ARGS((int argc,char *argv[],void *p));
  55. static int doquit __ARGS((int argc,char *argv[],void *p));
  56. static int dormdir __ARGS((int argc,char *argv[],void *p));
  57. static int doresume __ARGS((int argc,char *argv[],void *p));
  58. static int dorput __ARGS((int argc,char *argv[],void *p));
  59. static int dotype __ARGS((int argc,char *argv[],void *p));
  60. static int doview __ARGS((int argc,char *argv[],void *p));
  61. static int getline __ARGS((struct session *sp,char *prompt,char *buf,int n));
  62. static int getresp __ARGS((struct ftpcli *ftp,int mincode));
  63. static long getsub __ARGS((struct ftpcli *ftp,char *command,char *remotename,
  64.     char *localname));
  65. static long putsub __ARGS((struct ftpcli *ftp,char *remotename,char *localname,int putr));
  66. static void sendport __ARGS((int s,struct sockaddr_in *socket));
  67. static char *ftpcli_login __ARGS((struct ftpcli *ftp,char *host)); 
  68.  
  69. static char Notsess[] = "Not an FTP session!\n";
  70.  
  71. static int Ftp_type = ASCII_TYPE;
  72. static int Ftp_logbsize = 8;
  73.  
  74. static struct cmds Ftpcmds[] = {
  75.     "",             donothing,      0, 0, NULLCHAR,
  76.     "?",            doftphelp,      0, 0, NULLCHAR,
  77.     "ascii",        doascii,        0, 0, NULLCHAR,
  78.     "batch",        dobatch,        0, 0, NULLCHAR,
  79.     "binary",       dobinary,       0, 0, NULLCHAR,
  80.     "cd",           doftpcd,        0, 2, "cd <directory>",
  81.     "dir",          dolist,         0, 0, NULLCHAR,
  82.     "list",         dolist,         0, 0, NULLCHAR,
  83.     "get",          doget,          0, 2, "get <remotefile> <localfile>",
  84.     "hash",         dohash,         0, 0, NULLCHAR,
  85.     "help",         doftphelp,      0, 0, NULLCHAR,
  86.     "ls",           dols,           0, 0, NULLCHAR,
  87.     "lcd",          dolcd,          0, 1, NULLCHAR,
  88.     "ldir",         doldir,         0, 1, NULLCHAR,
  89.     "lmkdir",       dolmkdir,       0, 2, "lmkdir <local Directory>",
  90.     "mget",         domget,         0, 2, "mget <file> [<file> ...]",
  91.     "mkdir",        domkdir,        0, 2, "mkdir <directory>",
  92.     "mput",         domput,         0, 2, "mput <file> [<file> ...]",
  93.     "nlst",         dols,           0, 0, NULLCHAR,
  94.     "put",          doput,          0, 2, "put <localfile> <remotefile>",
  95.     "quit",         doquit,         0, 0, NULLCHAR,
  96.     "resume",       doresume,       0, 2, "resume <remotefile> <localfile>",
  97.     "rmdir",        dormdir,        0, 2, "rmdir <directory>",
  98.     "rput",         dorput,         0, 2, "rput <localfile> <remotefile>",
  99.     "type",         dotype,         0, 0, NULLCHAR,
  100.     "verbose",      doverbose,      0, 0, NULLCHAR,
  101.     "view",         doview,         0, 2,"view <remotefile>",
  102.     NULLCHAR,       NULLFP((int,char**,void*)), 0, 0, NULLCHAR,
  103. };
  104.  
  105. int
  106. doftphelp(argc,argv,p)
  107. int argc;
  108. char *argv[];
  109. void *p;
  110. {
  111.     register struct cmds *cmdp;
  112.     int i;
  113.     char buf[66];
  114.  
  115.     tprintf("\nFTP commands:\n");
  116.     memset(buf,' ',sizeof(buf));
  117.     buf[64] = '\n';
  118.     buf[65] = '\0';
  119.     for(i=0,cmdp = Ftpcmds;cmdp->name != NULL;cmdp++,i = (i+1)%4){
  120.         strncpy(&buf[i*16],cmdp->name,strlen(cmdp->name));
  121.         if(i == 3){
  122.             tprintf(buf);
  123.             memset(buf,' ',sizeof(buf));
  124.             buf[64] = '\n';
  125.             buf[65] = '\0';
  126.         }
  127.     }
  128.     if(i != 0)
  129.         tprintf(buf);
  130.     tprintf("\n");
  131.     return 0;
  132. }
  133.  
  134. /* Handle top-level FTP command */
  135. int
  136. doftp(argc,argv,p)
  137. int argc;
  138. char *argv[];
  139. void *p;
  140. {
  141.     struct session *sp;
  142.     struct ftpcli ftp;
  143.     struct sockaddr_in fsocket;
  144.     int resp,vsave;
  145.     char *buf,*bufsav,*cp,*un;
  146.     char prmt[40];
  147.     char l[17];
  148.     int control, rmt;
  149. #ifdef __GNUC__
  150.     static
  151. #endif
  152.     char *ftpcli_login __ARGS((struct ftpcli *, char *));
  153.     FILE *fp1 = NULLFILE;
  154.     struct  cur_dirs dirs;
  155.  
  156.     /* Only from console - WG7J */
  157.     if(Curproc->input != Command->input)
  158.     return 0;
  159.  
  160.     /* Allocate a session control block */
  161.     if((sp = newsession(argv[1],FTP,0)) == NULLSESSION){
  162.         tputs(TooManySessions);
  163.         return 1;
  164.     }
  165.     memset((char *)&ftp,0,sizeof(ftp));
  166.     ftp.control = ftp.data = -1;
  167.     ftp.verbose = V_BYTE;           /* Default changed by IW0CNB */
  168.     ftp.type = Ftp_type;
  169.     ftp.logbsize = Ftp_logbsize;
  170.  
  171.     sp->cb.ftp = &ftp;      /* Downward link */
  172.     ftp.session = sp;       /* Upward link */
  173.  
  174.     ftp.curdirs = &dirs;      
  175.  
  176.     fsocket.sin_family = AF_INET;
  177.     fsocket.sin_port = IPPORT_FTP;
  178.  
  179.     tprintf("Resolving %s... ",sp->name);
  180.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  181.         tprintf(Badhost,sp->name);
  182.         keywait(NULLCHAR,1);
  183.         freesession(sp);
  184.         return 1;
  185.     }
  186.  
  187.     /* Open the control connection */
  188.     if((control = sp->s = ftp.control = socket(AF_INET,SOCK_STREAM,0)) == -1){
  189.         tprintf("Can't create socket\n");
  190.         keywait(NULLCHAR,1);
  191.         freesession(sp);
  192.         return 1;
  193.     }
  194.  
  195.     sockmode(sp->s,SOCK_ASCII);
  196.     setflush(sp->s,-1);     /* Flush output only when we call getresp() */
  197.     tprintf("Trying %s...\n",psocket((struct sockaddr *)&fsocket));
  198.     tprintf("Local Directory - %s\n",init_dirs(&dirs));
  199.     if(connect(control,(char *)&fsocket,sizeof(fsocket)) == -1)
  200.         goto quit;
  201.     tprintf("FTP session %u connected to %s\n",(unsigned)(sp-Sessions),
  202.         sp->name);
  203.  
  204.     /* Wait for greeting from server */
  205.     resp = getresp(&ftp,200);
  206.  
  207.     if(resp >= 400)
  208.         goto quit;
  209. #ifdef UNIX
  210.     if (!(un = getenv("LOGNAME")))
  211. #endif
  212.     un = getenv("USER");
  213.         if(un != NULLCHAR)
  214.             sprintf(prmt,"Enter user name (%s): ",un);
  215.         else
  216.             sprintf(prmt,"Enter user name: ");
  217.     /* Now process responses and commands */
  218.     buf = mallocw(LINELEN);
  219.  
  220.     rmt = 0;
  221.     if(argc > 2){
  222.         if((fp1 = fopen(argv[2],READ_TEXT)) == NULLFILE) goto quit;
  223.     }
  224.     while(resp != -1){
  225.         if(resp == 220){
  226.             /* Sign-on banner; prompt for and send USER command */
  227.             if((cp = ftpcli_login(&ftp, sp->name)) == NULLCHAR){
  228. #ifndef notdef
  229.                   getline(sp,prmt,buf,LINELEN);
  230. #else
  231.                   getline(sp,"Enter user name: ",buf,LINELEN);
  232. #endif
  233.                 /* Send the command only if the user response
  234.                  * was non-null
  235.                  */
  236.                 if(buf[0] != '\n'){
  237.                     usprintf(control,"USER %s",buf);
  238.                     resp = getresp(&ftp,200);
  239.                 } else {
  240.                     if(un != NULLCHAR){
  241.                         usprintf(control,"USER %s\n",un);
  242.                         resp = getresp(&ftp,200);
  243.                     } else {
  244.                         tprintf("No username sent\n");
  245.                         resp = 200;     /* dummy */
  246.                     }
  247.                 }
  248.             } else {
  249.                 usprintf(control,"USER %s\n",cp);
  250.                 free(cp);
  251.                 resp = getresp(&ftp,200);
  252.             }
  253.         } else if(resp == 331){
  254.             if(ftp.password == NULLCHAR){
  255.                 /* turn off echo */
  256.                 sp->ttystate.echo = 0;
  257.                 getline(sp,"Password: ",buf,LINELEN);
  258.                 tprintf("\n");
  259.                 /* Turn echo back on */
  260.                 sp->ttystate.echo = 1;
  261.                 /* Send the command only if the user response
  262.                  * was non-null
  263.                  */
  264.                 if(buf[0] != '\n'){
  265.                     usprintf(control,"PASS %s",buf);
  266.                     resp = getresp(&ftp,200);
  267.                 } else {
  268.                     tprintf("Password must be provided.\nLogin failed.\n");
  269.                     resp = 200;     /* dummy */
  270.                 }
  271.             } else {
  272.                 usprintf(control,"PASS %s\n",ftp.password);
  273.                 resp = getresp(&ftp,200);
  274.                 free(ftp.password);
  275.                 ftp.password = NULLCHAR;        /* clean up */
  276.             }
  277.         } else if(resp == 399) {        /* Encrypted password login */
  278.             if(ftp.password == NULLCHAR){
  279.                 getline(sp,"Key ? --> ",buf,LINELEN);
  280.                 /* Send the command only if the user response
  281.                  * was non-null
  282.                  */
  283.                 if(buf[0] != '\n'){
  284.                     cp = strchr(ftp.line,':');
  285.                     cp += 2;
  286.                       /*  
  287.                     epass(htol(cp),buf,l);
  288.                       */  
  289.                     l[16] = '\0';
  290.                     free(ftp.line);
  291.                     ftp.line = NULLCHAR;
  292.                     usprintf(control,"PASS %s\n",l);
  293.                     resp = getresp(&ftp,200);
  294.                 } else {
  295.                     tprintf("Password must be provided.\nLogin failed.\n");
  296.                     resp = 200;     /* dummy */
  297.                 }
  298.             } else {
  299.                 cp = strchr(ftp.line,':');
  300.                 cp += 2;
  301.                 /*
  302.                 epass(htol(cp),ftp.password,l);
  303.                 */
  304.                 l[16] = '\0';
  305.                 free(ftp.line);
  306.                 ftp.line = NULLCHAR;
  307.                 usprintf(control,"PASS %s\n",l);
  308.                 resp = getresp(&ftp,200);
  309.                 free(ftp.password);
  310.                 ftp.password = NULLCHAR;        /* clean up */
  311.             }
  312.         } else {
  313.  
  314.             if (!rmt)
  315.             {
  316.             rmt = 1;
  317.             usprintf(control, "SYST\n");
  318.             usflush(control);
  319.             recvline(control, buf, LINELEN);
  320.             rip(buf);
  321.             if (atoi(buf) < 300)
  322.             {
  323.                 for (cp = buf + 4; *cp && *cp != ' '; cp++)
  324.                 ;
  325.                 *cp = '\0';
  326.                 tprintf("Remote system type is %s.\n", buf + 4);
  327.             }
  328.             while (buf[3] == '-')
  329.                 recvline(control, buf, LINELEN);
  330.             }
  331.  
  332.             /* Test the control channel first */
  333.             if(sockstate(control) == NULLCHAR)
  334.                 break;
  335.             if(argc > 2){
  336.                 if(fgets(buf,LINELEN,fp1) == NULLCHAR)
  337.                     goto quit;
  338.             } else
  339.                 getline(sp,"ftp> ",buf,LINELEN);
  340.  
  341.         /* Copy because cmdparse modifies the original */
  342.             bufsav = strdup(buf);
  343.             if((resp = cmdparse(Ftpcmds,buf,&ftp)) != -1){
  344.                 /* Valid command, free buffer and get another */
  345.                 free(bufsav);
  346.             } else if (ftp.state == EXITING_STATE)
  347.                 break;
  348.             else {
  349.                 /* Not a local cmd, send to remote server */
  350.                 usputs(control,bufsav);
  351.                 free(bufsav);
  352.  
  353.                 /* Enable display of server response */
  354.                 vsave = ftp.verbose;
  355.                 ftp.verbose = V_NORMAL;
  356.                 resp = getresp(&ftp,200);
  357.                 ftp.verbose = vsave;
  358.             }
  359.         }
  360.     }
  361.     free(buf);
  362. quit:   cp = sockerr(control);
  363.     tprintf("FTP session %u closed: %s\n",(unsigned)(sp - Sessions),
  364.      cp != NULLCHAR ? cp : "EOF");
  365.  
  366.     if(ftp.fp != NULLFILE && ftp.fp != stdout)
  367.         fclose(ftp.fp);
  368.     if(ftp.data != -1)
  369.         close_s(ftp.data);
  370.     if(ftp.control != -1)
  371.         close_s(ftp.control);
  372.     if(argc < 3)
  373.         keywait(NULLCHAR,1);
  374.     else
  375.         fclose(fp1);
  376.     if(ftp.session != NULLSESSION)
  377.         freesession(ftp.session);
  378.     free_dirs(&dirs);         
  379.     return 0;
  380. }
  381.  
  382. /* Control verbosity level */
  383. static int
  384. doverbose(argc,argv,p)
  385. int argc;
  386. char *argv[];
  387. void *p;
  388. {
  389.     register struct ftpcli *ftp;
  390.  
  391.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  392.         return -1;
  393.     return setshort(&ftp->verbose,"Verbose",argc,argv);
  394. }
  395. /* Enable/disable command batching */
  396. static int
  397. dobatch(argc,argv,p)
  398. int argc;
  399. char *argv[];
  400. void *p;
  401. {
  402.     register struct ftpcli *ftp;
  403.  
  404.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  405.         return -1;
  406.     return setbool(&ftp->batch,"Command batching",argc,argv);
  407. }
  408. /* Set verbosity to high (convenience command) */
  409. static int
  410. dohash(argc,argv,p)
  411. int argc;
  412. char *argv[];
  413. void *p;
  414. {
  415.     register struct ftpcli *ftp;
  416.  
  417.     if((ftp = (struct ftpcli *)p) == NULLFTP)
  418.         return -1;
  419.     tputs("Hash Printing ");
  420.     if (ftp->verbose==V_HASH){
  421.         ftp->verbose = V_HASH+1;
  422.         tputs("Off\n");
  423.     } else {
  424.         tputs("On\n");
  425.         ftp->verbose = V_HASH;
  426.     }
  427.     return 0;
  428. }
  429.     
  430. /* Close session */
  431. static int
  432. doquit(argc,argv,p)
  433. int argc;
  434. char *argv[];
  435. void *p;
  436. {
  437.     register struct ftpcli *ftp;
  438.  
  439.     ftp = (struct ftpcli *)p;
  440.     if(ftp == NULLFTP)
  441.         return -1;
  442.     usprintf(ftp->control,"QUIT\n");
  443.  
  444.     getresp(ftp,200);       /* Get the closing message */
  445.     getresp(ftp,200);       /* Wait for the server to close */
  446.     /* prevent spurious retry caused by "error" return */
  447.     ftp->state = EXITING_STATE;
  448.     return -1;
  449. }
  450.  
  451. /* Translate 'cd' to 'cwd' for convenience */
  452. static int
  453. doftpcd(argc,argv,p)
  454. int argc;
  455. char *argv[];
  456. void *p;
  457. {
  458.     register struct ftpcli *ftp;
  459.  
  460.     ftp = (struct ftpcli *)p;
  461.     if(ftp == NULLFTP)
  462.         return -1;
  463.     usprintf(ftp->control,"CWD %s\n",argv[1]);
  464.     return getresp(ftp,200);
  465. }
  466. /* Translate 'mkdir' to 'xmkd' for convenience */
  467. static int
  468. domkdir(argc,argv,p)
  469. int argc;
  470. char *argv[];
  471. void *p;
  472. {
  473.     register struct ftpcli *ftp;
  474.  
  475.     ftp = (struct ftpcli *)p;
  476.     if(ftp == NULLFTP)
  477.         return -1;
  478.     usprintf(ftp->control,"XMKD %s\n",argv[1]);
  479.     return getresp(ftp,200);
  480. }
  481. /* Translate 'rmdir' to 'xrmd' for convenience */
  482. static int
  483. dormdir(argc,argv,p)
  484. int argc;
  485. char *argv[];
  486. void *p;
  487. {
  488.     register struct ftpcli *ftp;
  489.  
  490.     ftp = (struct ftpcli *)p;
  491.     if(ftp == NULLFTP)
  492.         return -1;
  493.     usprintf(ftp->control,"XRMD %s\n",argv[1]);
  494.     return getresp(ftp,200);
  495. }
  496. static int
  497. dobinary(argc,argv,p)
  498. int argc;
  499. char *argv[];
  500. void *p;
  501. {
  502.     char *args[2];
  503.  
  504.     args[1] = "I";
  505.     return dotype(2,args,p);
  506. }
  507. static int
  508. doascii(argc,argv,p)
  509. int argc;
  510. char *argv[];
  511. void *p;
  512. {
  513.     char *args[2];
  514.  
  515.     args[1] = "A";
  516.     return dotype(2,args,p);
  517. }
  518.  
  519. /* Handle "type" command from user */
  520. static int
  521. dotype(argc,argv,p)
  522. int argc;
  523. char *argv[];
  524. void *p;
  525. {
  526.     register struct ftpcli *ftp;
  527.  
  528.     ftp = (struct ftpcli *)p;
  529.     if(ftp == NULLFTP)
  530.         return -1;
  531.     if(argc < 2){
  532.         switch(ftp->type){
  533.         case IMAGE_TYPE:
  534.             tprintf("Image\n");
  535.             break;
  536.         case ASCII_TYPE:
  537.             tprintf("Ascii\n");
  538.             break;
  539.         case LOGICAL_TYPE:
  540.             tprintf("Logical bytesize %u\n",ftp->logbsize);
  541.             break;
  542.         }
  543.         return 0;
  544.     }
  545.     switch(*argv[1]){
  546.     case 'i':
  547.     case 'I':
  548.     case 'b':
  549.     case 'B':
  550.         ftp->type = IMAGE_TYPE;
  551.         break;
  552.     case 'a':
  553.     case 'A':
  554.         ftp->type = ASCII_TYPE;
  555.         break;
  556.     case 'L':
  557.     case 'l':
  558.         ftp->type = LOGICAL_TYPE;
  559.         ftp->logbsize = atoi(argv[2]);
  560.         break;
  561.     default:
  562.         tprintf("Invalid type %s\n",argv[1]);
  563.         return 1;
  564.     }
  565.     return 0;
  566. }
  567.  
  568. /* Handle "ftype" command */
  569. int
  570. doftype(argc,argv,p)
  571. int argc;
  572. char *argv[];
  573. void *p;
  574. {
  575.     if(argc < 2){
  576.         tprintf("Ftp initial TYPE is ");
  577.         switch(Ftp_type){
  578.         case IMAGE_TYPE:
  579.             tprintf("Image\n");
  580.             break;
  581.         case ASCII_TYPE:
  582.             tprintf("Ascii\n");
  583.             break;
  584.         case LOGICAL_TYPE:
  585.             tprintf("Logical bytesize %u\n",Ftp_logbsize);
  586.             break;
  587.         }
  588.         return 0;
  589.     }
  590.     switch(*argv[1]){
  591.     case 'i':
  592.     case 'I':
  593.     case 'b':
  594.     case 'B':
  595.         Ftp_type = IMAGE_TYPE;
  596.         break;
  597.     case 'a':
  598.     case 'A':
  599.         Ftp_type = ASCII_TYPE;
  600.         break;
  601.     case 'L':
  602.     case 'l':
  603.         Ftp_type = LOGICAL_TYPE;
  604.         Ftp_logbsize = atoi(argv[2]);
  605.         break;
  606.     default:
  607.         tprintf("Invalid type %s\n",argv[1]);
  608.         return 1;
  609.     }
  610.     return 0;
  611. }
  612.  
  613. /* View added to jnos1.08 by Simon G1FHY _ mod by Paul@wolf.demon.co.uk */
  614. /* Start view transfer. Syntax: view <remote name> */
  615. static int
  616. doview(argc,argv,p)
  617. int argc;
  618. char *argv[];
  619. void *p;
  620. {
  621.     char *remotename;
  622.     register struct ftpcli  *ftp;
  623.  
  624.     ftp = (struct ftpcli *)p;
  625.     if(ftp == NULLFTP){
  626.         tprintf(Notsess);
  627.         return 1;
  628.     }
  629.     remotename = argv[1];
  630.  
  631.     getsub(ftp,"RETR",remotename,NULLCHAR);
  632.     return 0;
  633. }
  634. /* Start receive transfer. Syntax: get <remote name> [<local name>] */
  635. static int
  636. doget(argc,argv,p)
  637. int argc;
  638. char *argv[];
  639. void *p;
  640. {
  641.     char *remotename,*localname;
  642.     register struct ftpcli *ftp;
  643.  
  644.     ftp = (struct ftpcli *)p;
  645.     if(ftp == NULLFTP){
  646.         tprintf(Notsess);
  647.         return 1;
  648.     }
  649.     remotename = argv[1];
  650.     if(argc < 3)
  651.         localname = remotename;
  652.     else
  653.         localname = argv[2];
  654.  
  655.     getsub(ftp,"RETR",remotename,localname);
  656.     return 0;
  657. }
  658. /* Get a collection of files */
  659. static int
  660. domget(argc,argv,p)
  661. int argc;
  662. char *argv[];
  663. void *p;
  664. {
  665.     register struct ftpcli *ftp;
  666.     FILE *files, *filel;
  667.     char tmpname[80];
  668.     char *buf, *local;
  669. #ifdef MSDOS
  670.     char *c;
  671. #endif
  672.     int i, inlist;
  673.     long r;
  674.  
  675.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  676.         tprintf(Notsess);
  677.         return 1;
  678.     }
  679.     tmpnam(tmpname);
  680.     buf = mallocw(DIRBUF);
  681.     ftp->state = RECEIVING_STATE;
  682.     for(i=1;i<argc;i++){
  683.         if(argv[i][0] == '@'){
  684.             inlist = 1;
  685.             if((filel = fopen(make_fname(ftp->curdirs->dir,&argv[i][1]), "r")) == NULLFILE){
  686.                 tprintf("Can't open listfile: %s\n", &argv[i][1]);
  687.                 continue;
  688.             }
  689.             if((files = fopen(tmpname, "w")) == NULLFILE){
  690.                 tprintf("Can't open tempfile: %s\n", tmpname);
  691.                 continue;
  692.             }
  693.             while(fgets(buf,DIRBUF,filel) != NULLCHAR){
  694.                 fputs(buf,files);
  695.             }
  696.             fclose(files);
  697.             fclose(filel);
  698.             if((files = fopen(tmpname, "r")) == NULLFILE){
  699.                 tprintf("Can't open tempfile: %s\n", tmpname);
  700.                 continue;
  701.             }
  702.         } else {
  703.             inlist = 0;
  704.             r = getsub(ftp,"NLST",argv[i],tmpname);
  705.             if(ftp->abort)
  706.                 break;  /* Aborted */
  707.             if(r == -1 || (files = fopen(tmpname,"r")) == NULLFILE){
  708.                 tprintf("Can't NLST %s\n",argv[i]);
  709.                 unlink(tmpname);
  710.                 continue;
  711.             }
  712.         }
  713.         /* The tmp file now contains a list of the remote files, so
  714.          * go get 'em. Break out if the user signals an abort.
  715.          */
  716.         while(fgets(buf,DIRBUF,files) != NULLCHAR){
  717.             rip(buf);
  718.             local = strdup(buf);
  719. #ifdef  MSDOS
  720.             if(inlist){
  721.                 strrev(local);
  722.                 strtok(local, "\\/[]<>,?#~()&%");
  723.                 strrev(local);
  724.             }
  725.             if((c = strstr(local, ".")) != NULLCHAR) {
  726.                 c++;
  727.                 c = strtok(c, ".");     /* remove 2nd period if any*/
  728.             }
  729. #endif
  730.             getsub(ftp,"RETR",buf,local);
  731.             free(local);
  732.             if(ftp->abort){
  733.                 /* User abort */
  734.                 ftp->abort = 0;
  735.                 fclose(files);
  736.                 unlink(tmpname);
  737.                 free(buf);
  738.                 ftp->state = COMMAND_STATE;
  739.                 return 1;
  740.             }
  741.         }
  742.         fclose(files);
  743.         unlink(tmpname);
  744.     }
  745.     free(buf);
  746.     ftp->state = COMMAND_STATE;
  747.     ftp->abort = 0;
  748.     return 0;
  749. }
  750. /* Resume interrupted file transfer. Syntax: resume <remote name> [<local name>] */
  751. static int
  752. doresume(argc,argv,p)
  753. int argc;
  754. char *argv[];
  755. void *p;
  756. {
  757.     char *remotename,*localname;
  758.     register struct ftpcli *ftp;
  759.  
  760.     ftp = (struct ftpcli *)p;
  761.     if(ftp == NULLFTP){
  762.         tprintf(Notsess);
  763.         return 1;
  764.     }
  765.     remotename = argv[1];
  766.     if(argc < 3)
  767.         localname = remotename;
  768.     else
  769.         localname = argv[2];
  770.  
  771.     getsub(ftp,"RSME",remotename,localname);
  772.     return 0;
  773. }
  774. /* List remote directory. Syntax: dir <remote files> [<local name>] */
  775. static int
  776. dolist(argc,argv,p)
  777. int argc;
  778. char *argv[];
  779. void *p;
  780. {
  781.     char *remotename,*localname;
  782.     register struct ftpcli *ftp;
  783.  
  784.     ftp = (struct ftpcli *)p;
  785.     if(ftp == NULLFTP){
  786.         tprintf(Notsess);
  787.         return 1;
  788.     }
  789.     remotename = argv[1];
  790.     if(argc > 2)
  791.         localname = argv[2];
  792.     else
  793.         localname = NULLCHAR;
  794.  
  795.     getsub(ftp,"LIST",remotename,localname);
  796.     return 0;
  797. }
  798. /* Remote directory list, short form. Syntax: ls <remote files> [<local name>] */
  799. static int
  800. dols(argc,argv,p)
  801. int argc;
  802. char *argv[];
  803. void *p;
  804. {
  805.     char *remotename,*localname;
  806.     register struct ftpcli *ftp;
  807.  
  808.     ftp = (struct ftpcli *)p;
  809.     if(ftp == NULLFTP){
  810.         tprintf(Notsess);
  811.         return 1;
  812.     }
  813.     remotename = argv[1];
  814.     if(argc > 2)
  815.         localname = argv[2];
  816.     else
  817.         localname = NULLCHAR;
  818.  
  819.     getsub(ftp,"NLST",remotename,localname);
  820.     return 0;
  821. }
  822. /* Common code to LIST/NLST/RETR/RSME and mget
  823.  * Returns number of bytes received if successful
  824.  * Returns -1 on error
  825.  */
  826. static long
  827. getsub(ftp,command,remotename,localname)
  828. register struct ftpcli *ftp;
  829. char *command,*remotename,*localname;
  830. {
  831.     unsigned long total;
  832.     FILE *fp;
  833.     int cnt,resp,i,control,savmode;
  834.     char *mode;
  835.     struct sockaddr_in lsocket;
  836.     struct sockaddr_in lcsocket;
  837.     int32 startclk,rate;
  838.     int vsave;
  839.     int typewait = 0;
  840.     int prevstate;
  841.     long starting;
  842.  
  843.     if(ftp == NULLFTP)
  844.         return -1;
  845.     control = ftp->control;
  846.     savmode = ftp->type;
  847. #ifdef __GNUC__
  848.     mode = 0;        /* semi-spurious warning */
  849. #endif
  850.  
  851.     switch(ftp->type){
  852.     case IMAGE_TYPE:
  853.     case LOGICAL_TYPE:
  854.         if(strcmp(command,"RSME") == 0)
  855.             mode = APPEND_BINARY;
  856.         else
  857.             mode = WRITE_BINARY;
  858.         break;
  859.     case ASCII_TYPE:
  860.         if(strcmp(command,"RSME") == 0)
  861.             mode = APPEND_TEXT;
  862.         else
  863.             mode = WRITE_TEXT;
  864.         break;
  865.     }
  866.     /* Open the file */
  867.     if(localname == NULLCHAR){
  868.         fp = NULLFILE;
  869.     } else if((fp = fopen(make_fname(ftp->curdirs->dir,localname),mode)) == NULLFILE){
  870.         tprintf("Can't write %s: %s\n",localname,sys_errlist[errno]);
  871.         return -1;
  872.     }
  873.     /* Open the data connection */
  874.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  875.     listen(ftp->data,0);    /* Accept only one connection */
  876.     prevstate = ftp->state;
  877.     ftp->state = RECEIVING_STATE;
  878.  
  879.     /* Send TYPE message, if necessary */
  880.     if(strcmp(command,"LIST") == 0 || strcmp(command,"NLST") == 0){
  881.         /* Directory listings are always in ASCII */
  882.         ftp->type = ASCII_TYPE;
  883.     }
  884.     if(ftp->typesent != ftp->type){
  885.         switch(ftp->type){
  886.         case ASCII_TYPE:
  887.             usprintf(control,"TYPE A\n");
  888.             break;
  889.         case IMAGE_TYPE:
  890.             usprintf(control,"TYPE I\n");
  891.             break;
  892.         case LOGICAL_TYPE:
  893.             usprintf(control,"TYPE L %d\n",ftp->logbsize);
  894.             break;
  895.         }
  896.         ftp->typesent = ftp->type;
  897.         if(!ftp->batch){
  898.             resp = getresp(ftp,200);
  899.             if(resp == -1 || resp > 299)
  900.                 goto failure;
  901.         } else
  902.             typewait = 1;
  903.     }
  904.     /* Send the PORT message. Use the IP address
  905.      * on the local end of our control connection.
  906.      */
  907.     i = SOCKSIZE;
  908.     getsockname(ftp->data,(char *)&lsocket,&i); /* Get port number */
  909.     i = SOCKSIZE;
  910.     getsockname(ftp->control,(char *)&lcsocket,&i);
  911.     lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
  912.     sendport(control,&lsocket);
  913.     if(!ftp->batch){
  914.         /* Get response to PORT command */
  915.         resp = getresp(ftp,200);
  916.         if(resp == -1 || resp > 299)
  917.             goto failure;
  918.     }
  919.     /* Generate the command to start the transfer */
  920.     if(remotename != NULLCHAR)
  921.         usprintf(control,"%s %s\n",command,remotename);
  922.     else
  923.         usprintf(control,"%s\n",command);
  924.  
  925.     if(ftp->batch){
  926.         /* Get response to TYPE command, if sent */
  927.         if(typewait){
  928.             resp = getresp(ftp,200);
  929.             if(resp == -1 || resp > 299)
  930.                 goto failure;
  931.         }
  932.         /* Get response to PORT command */
  933.         resp = getresp(ftp,200);
  934.         if(resp == -1 || resp > 299)
  935.             goto failure;
  936.     }
  937.     /* Get the intermediate "150" response */
  938.     resp = getresp(ftp,100);
  939.     if(resp == -1 || resp >= 400)
  940.         goto failure;
  941.  
  942.     /* Wait for the server to open the data connection */
  943.     cnt = 0;
  944.     accept(ftp->data,NULLCHAR,(int *)NULL);
  945.     startclk = msclock();
  946.  
  947.     /* If output is to the screen, temporarily disable hash marking */
  948.     vsave = ftp->verbose;
  949.     if(vsave >= V_HASH && fp == NULLFILE)
  950.         ftp->verbose = V_NORMAL;
  951.  
  952.     if(strcmp(command,"RSME") == 0){
  953.         if((starting = getsize(fp)) == -1)
  954.             starting = 0L;
  955.         usprintf(control,"%ld %lu\n",starting,checksum(fp,starting));
  956.         usflush(control);
  957.         fseek(fp,starting,SEEK_SET);
  958.     }
  959.     total = recvfile(fp,ftp->data,ftp->type,(ftp->verbose >= V_HASH) ? ftp->verbose : 0);
  960.     /* Immediately close the data connection; some servers (e.g., TOPS-10)
  961.      * wait for the data connection to close completely before returning
  962.      * the completion message on the control channel
  963.      */
  964.     close_s(ftp->data);
  965.     ftp->data = -1;
  966.  
  967. #ifdef  CPM
  968.     if(fp != NULLFILE && ftp->type == ASCII_TYPE)
  969.         putc(CTLZ,fp);
  970. #endif
  971.     if(fp != NULLFILE && fp != stdout)
  972.         fclose(fp);
  973.     if(remotename == NULLCHAR)
  974.         remotename = "";
  975.     if(total == -1){
  976.         tprintf("%s %s: Error/abort during data transfer\n",command,remotename);
  977.     } else if(ftp->verbose >= V_SHORT){
  978.         startclk = msclock() - startclk;
  979.         rate = 0;
  980.         if(startclk != 0){      /* Avoid divide-by-zero */
  981.             if(total < 4294967L){
  982.                 rate = (total*1000)/startclk;
  983.             } else {        /* Avoid overflow */
  984.                 rate = total/(startclk/1000);
  985.             }
  986.         }
  987.         tprintf("%s %s: %lu bytes in %lu sec (%lu/sec)\n",
  988.          command,remotename, total,startclk/1000,rate);
  989.     }
  990.     /* Get the "Sent" message */
  991.     getresp(ftp,200);
  992.  
  993.     ftp->state = prevstate;
  994.     ftp->verbose = vsave;
  995.     ftp->type = savmode;
  996.     return total;
  997.  
  998. failure:
  999.     /* Error, quit */
  1000.     if(fp != NULLFILE && fp != stdout)
  1001.         fclose(fp);
  1002.     close_s(ftp->data);
  1003.     ftp->data = -1;
  1004.     ftp->state = prevstate;
  1005.     ftp->type = savmode;
  1006.     return -1;
  1007. }
  1008. /* Send a file. Syntax: put <local name> [<remote name>] */
  1009. static int
  1010. doput(argc,argv,p)
  1011. int argc;
  1012. char *argv[];
  1013. void *p;
  1014. {
  1015.     register struct ftpcli *ftp;
  1016.     char *remotename,*localname;
  1017.  
  1018.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  1019.         tprintf(Notsess);
  1020.         return 1;
  1021.     }
  1022.     localname = argv[1];
  1023.     if(argc < 3)
  1024.         remotename = localname;
  1025.     else
  1026.         remotename = argv[2];
  1027.  
  1028.     putsub(ftp,remotename,localname,0);
  1029.     return 0;
  1030. }
  1031. /* Put a collection of files */
  1032. static int
  1033. domput(argc,argv,p)
  1034. int argc;
  1035. char *argv[];
  1036. void *p;
  1037. {
  1038.     register struct ftpcli *ftp;
  1039.     FILE *files;
  1040.     int i,j;
  1041.     char tmpname[80];       
  1042.     char *buf,*file;
  1043.  
  1044.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  1045.         tprintf(Notsess);
  1046.         return 1;
  1047.     }
  1048.     tmpnam(tmpname);
  1049.     if((files = fopen(tmpname,"w+")) == NULLFILE){
  1050.         tprintf("Can't list local files\n");
  1051.         unlink(tmpname);
  1052.         return 1;
  1053.     }
  1054.  
  1055.     for(i=1;i<argc;i++) {
  1056.     /* Use the path in the ftp client struct, since user may have done
  1057.      * a lcd command to change dir !
  1058.      */
  1059.     file = pathname(ftp->curdirs->dir,argv[i]);
  1060.     /* Shift everything back one byte, pathname returns with a leading '/'! */
  1061.     for(j=1;j<=strlen(file);j++)
  1062.         file[j-1] = file[j];
  1063.     getdir(file,0,files);
  1064.     free(file);
  1065.     }
  1066.     rewind(files);
  1067.     buf = mallocw(DIRBUF);
  1068.     ftp->state = SENDING_STATE;
  1069.     while(fgets(buf,DIRBUF,files) != NULLCHAR){
  1070.         rip(buf);
  1071.         putsub(ftp,buf,buf,0);
  1072.         if(ftp->abort)
  1073.             break;          /* User abort */
  1074.     }
  1075.     fclose(files);
  1076.     unlink(tmpname);
  1077.     free(buf);
  1078.     ftp->state = COMMAND_STATE;
  1079.     ftp->abort = 0;
  1080.     return 0;
  1081. }
  1082. /* Put a file, appending data to it - iw0cnb */
  1083. static int
  1084. dorput(argc,argv,p)
  1085. int argc;
  1086. char *argv[];
  1087. void *p;
  1088. {
  1089.     register struct ftpcli *ftp;
  1090.     char *remotename,*localname;
  1091.  
  1092.     if((ftp = (struct ftpcli *)p) == NULLFTP){
  1093.         tprintf(Notsess);
  1094.         return 1;
  1095.     }
  1096.     localname = argv[1];
  1097.     if(argc < 3)
  1098.         remotename = localname;
  1099.     else
  1100.         remotename = argv[2];
  1101.  
  1102.     putsub(ftp,remotename,localname,1);
  1103.     return 0;
  1104. }
  1105. /* Common code to put, mput, rput.
  1106.  * Returns number of bytes sent if successful
  1107.  * Returns -1 on error
  1108.  */
  1109. static long
  1110. putsub(ftp,remotename,localname,putr)
  1111. register struct ftpcli *ftp;
  1112. char *remotename,*localname;
  1113. int putr;       /* Flag: 0 if standard put, 1 if put with resume */
  1114. {
  1115.     char *mode;
  1116.     int i,resp,control;
  1117.     unsigned long total;
  1118.     FILE *fp;
  1119.     struct sockaddr_in lsocket,lcsocket;
  1120.     int32 startclk,rate;
  1121.     int typewait = 0;
  1122.     int prevstate;
  1123.     char *line;
  1124.     long starting;
  1125.     unsigned long check, local_check;
  1126.  
  1127.     control = ftp->control;
  1128.     if(ftp->type == IMAGE_TYPE)
  1129.         mode = READ_BINARY;
  1130.     else
  1131.         mode = READ_TEXT;
  1132.  
  1133.     /* Open the file */
  1134.     if((fp = fopen(make_fname(ftp->curdirs->dir,localname),mode)) == NULLFILE){
  1135.         tprintf("Can't read %s: %s\n",localname,sys_errlist[errno]);
  1136.         return -1;
  1137.     }
  1138.     if(ftp->type == ASCII_TYPE && isbinary(fp)){
  1139.         tprintf("Warning: type is ASCII and %s appears to be binary\n",localname);
  1140.     }
  1141.     /* Open the data connection */
  1142.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  1143.     listen(ftp->data,0);
  1144.     prevstate = ftp->state;
  1145.     ftp->state = SENDING_STATE;
  1146.  
  1147.     /* Send TYPE message, if necessary */
  1148.     if(ftp->typesent != ftp->type){
  1149.         switch(ftp->type){
  1150.         case ASCII_TYPE:
  1151.             usprintf(control,"TYPE A\n");
  1152.             break;
  1153.         case IMAGE_TYPE:
  1154.             usprintf(control,"TYPE I\n");
  1155.             break;
  1156.         case LOGICAL_TYPE:
  1157.             usprintf(control,"TYPE L %d\n",ftp->logbsize);
  1158.             break;
  1159.         }
  1160.         ftp->typesent = ftp->type;
  1161.  
  1162.         /* Get response to TYPE command */
  1163.         if(!ftp->batch){
  1164.             resp = getresp(ftp,200);
  1165.             if(resp == -1 || resp > 299){
  1166.                 goto failure;
  1167.             }
  1168.         } else
  1169.             typewait = 1;
  1170.     }
  1171.     /* Send the PORT message. Use the IP address
  1172.      * on the local end of our control connection.
  1173.      */
  1174.     i = SOCKSIZE;
  1175.     getsockname(ftp->data,(char *)&lsocket,&i);
  1176.     i = SOCKSIZE;
  1177.     getsockname(ftp->control,(char *)&lcsocket,&i);
  1178.     lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
  1179.     sendport(control,&lsocket);
  1180.     if(!ftp->batch){
  1181.         /* Get response to PORT command */
  1182.         resp = getresp(ftp,200);
  1183.         if(resp == -1 || resp > 299){
  1184.             goto failure;
  1185.         }
  1186.     }
  1187.     /* Generate the command to start the transfer */
  1188.     if(putr == 1)
  1189.         usprintf(control,"RPUT %s\n",remotename);
  1190.     else
  1191.         usprintf(control,"STOR %s\n",remotename);
  1192.  
  1193.     if(ftp->batch){
  1194.         /* Get response to TYPE command, if sent */
  1195.         if(typewait){
  1196.             resp = getresp(ftp,200);
  1197.             if(resp == -1 || resp > 299){
  1198.                 goto failure;
  1199.             }
  1200.         }
  1201.         /* Get response to PORT command */
  1202.         resp = getresp(ftp,200);
  1203.         if(resp == -1 || resp > 299){
  1204.             goto failure;
  1205.         }
  1206.     }
  1207.     /* Get the intermediate "150" response */
  1208.     resp = getresp(ftp,100);
  1209.     if(resp == -1 || resp >= 400){
  1210.         goto failure;
  1211.     }
  1212.  
  1213.     /* Wait for the data connection to open. Otherwise the first
  1214.      * block of data would go out with the SYN, and this may confuse
  1215.      * some other TCPs
  1216.      */
  1217.     accept(ftp->data,NULLCHAR,(int *)NULL);
  1218.  
  1219.     startclk = msclock();
  1220.     if(putr == 1){          /* Wait for file offset and checksum */
  1221.         line=mallocw(40);
  1222.         recvline(control,line,40);
  1223.         starting=atol(line);
  1224.         check = (unsigned long)atol(strchr(line,' '));
  1225.         free(line);
  1226.         local_check = checksum(fp,starting);
  1227.         if(ftp->verbose >= V_HASH)
  1228.             tprintf("Remote checksum: %lu Local checksum: %lu Offset: %ld\n",check,local_check,starting);
  1229.         check -= local_check;
  1230.         if(check != 0){
  1231.             tprintf("Can't send %s: files are different\n",localname);
  1232.             shutdown(ftp->data,1);
  1233.             getresp(ftp,200);
  1234.             goto failure;
  1235.         }
  1236.     }
  1237.  
  1238.     total = sendfile(fp,ftp->data,ftp->type,(ftp->verbose >= V_HASH) ? ftp->verbose : 0);
  1239.     close_s(ftp->data);
  1240.     ftp->data = -1;
  1241.     fclose(fp);
  1242.  
  1243.     /* Wait for control channel ack before calculating transfer time;
  1244.      * this accounts for transmitted data in the pipe.
  1245.      */
  1246.     getresp(ftp,200);
  1247.  
  1248.     if(total == -1){
  1249.         tprintf("STOR %s: Error/abort during data transfer\n",remotename);
  1250.     } else if(ftp->verbose >= V_SHORT){
  1251.         startclk = msclock() - startclk;
  1252.         rate = 0;
  1253.         if(startclk != 0){      /* Avoid divide-by-zero */
  1254.             if(total < 4294967L){
  1255.                 rate = (total*1000)/startclk;
  1256.             } else {        /* Avoid overflow */
  1257.                 rate = total/(startclk/1000);
  1258.             }
  1259.         }
  1260.         tprintf("STOR %s: %lu bytes in %lu sec (%lu/sec)\n",
  1261.          remotename,total,startclk/1000,rate);
  1262.     }
  1263.     ftp->state = prevstate;
  1264.     return total;
  1265.  
  1266. failure:
  1267.     /* Error, quit */
  1268.     fclose(fp);
  1269.     close_s(ftp->data);
  1270.     ftp->data = -1;
  1271.     ftp->state = prevstate;
  1272.     return -1;
  1273. }
  1274. /* Abort a GET or PUT operation in progress. Note: this will leave
  1275.  * the partial file on the local or remote system
  1276.  */
  1277. int
  1278. doabort(argc,argv,p)
  1279. int argc;
  1280. char *argv[];
  1281. void *p;
  1282. {
  1283.     register struct session *sp;
  1284.     register struct ftpcli *ftp;
  1285.  
  1286.     sp = (struct session *)p;
  1287.     if(sp == NULLSESSION)
  1288.         return -1;
  1289.  
  1290.     /* Default is the current session, but it can be overridden with
  1291.      * an argument.
  1292.      */
  1293.     if(argc > 1)
  1294.         sp = sessptr(argv[1]);
  1295.  
  1296.     if(sp == NULLSESSION || sp->type != FTP){
  1297.         tprintf("Not an active FTP session\n");
  1298.         return 1;
  1299.     }
  1300.     ftp = sp->cb.ftp;
  1301.     switch(ftp->state){
  1302.     case COMMAND_STATE:
  1303.         tprintf("No active transfer\n");
  1304.         return 1;
  1305.     case SENDING_STATE:
  1306.         /* Send a premature EOF.
  1307.          * Unfortunately we can't just reset the connection
  1308.          * since the remote side might end up waiting forever
  1309.          * for us to send something.
  1310.          */
  1311.         shutdown(ftp->data,1);  /* Note fall-thru */
  1312.         ftp->abort = 1;
  1313.         break;
  1314.     case RECEIVING_STATE:
  1315.         /* Just blow away the receive socket */
  1316.         shutdown(ftp->data,2);  /* Note fall-thru */
  1317.         ftp->abort = 1;
  1318.         break;
  1319.     }
  1320.     return 0;
  1321. }
  1322. /* send PORT message */
  1323. static void
  1324. sendport(s,socket)
  1325. int s;
  1326. struct sockaddr_in *socket;
  1327. {
  1328.     /* Send PORT a,a,a,a,p,p message */
  1329.     usprintf(s,"PORT %u,%u,%u,%u,%u,%u\n",
  1330.         hibyte(hiword(socket->sin_addr.s_addr)),
  1331.         lobyte(hiword(socket->sin_addr.s_addr)),
  1332.         hibyte(loword(socket->sin_addr.s_addr)),
  1333.         lobyte(loword(socket->sin_addr.s_addr)),
  1334.         hibyte(socket->sin_port),
  1335.         lobyte(socket->sin_port));
  1336. }
  1337.  
  1338. /* Wait for, read and display response from FTP server. Return the result code.
  1339.  */
  1340. static int
  1341. getresp(ftp,mincode)
  1342. struct ftpcli *ftp;
  1343. int mincode;    /* Keep reading until at least this code comes back */
  1344. {
  1345.     register char *line;
  1346.     int rval;
  1347.  
  1348.     usflush(ftp->control);
  1349.     line = mallocw(LINELEN);
  1350.     for(;;){
  1351.         /* Get line */
  1352.         if(recvline(ftp->control,line,LINELEN) == -1){
  1353.             rval = -1;
  1354.             break;
  1355.         }
  1356.         rip(line);              /* Remove cr/lf */
  1357.         rval = atoi(line);
  1358.         if(rval >= 400 || ftp->verbose >= V_NORMAL)
  1359.             tprintf("%s\n",line);   /* Display to user */
  1360.  
  1361.         /* Messages with dashes are continued */
  1362.         if(line[3] != '-' && rval >= mincode)
  1363.             break;
  1364.     }
  1365.     if(rval == 399){        /* Return encrypted password */
  1366.         ftp->line = mallocw(LINELEN);
  1367.         strcpy(ftp->line,line);
  1368.     }
  1369.     free(line);
  1370.     return rval;
  1371. }
  1372.  
  1373. /* Issue a prompt and read a line from the user */
  1374. static int
  1375. getline(sp,prompt,buf,n)
  1376. struct session *sp;
  1377. char *prompt;
  1378. char *buf;
  1379. int n;
  1380. {
  1381.     /* If there's something already there, don't issue prompt */
  1382.     if(socklen(sp->input,0) == 0)
  1383.         tprintf(prompt);
  1384.  
  1385.     usflush(sp->output);
  1386.     return recvline(sp->input,buf,(unsigned)n);
  1387. }
  1388.  
  1389. /* Attempt to log in the user whose name is in ftp->username and password
  1390.  * in pass
  1391.  */
  1392. static char *
  1393. ftpcli_login(ftp,host)
  1394. struct ftpcli *ftp;
  1395. char *host; {
  1396.  
  1397.     char buf[80],*cp,*cp1;
  1398.     FILE *fp;
  1399.  
  1400.     extern char *Hostfile;  /* List of user names and permissions */
  1401.  
  1402.     if((fp = fopen(Hostfile,"r")) == NULLFILE){
  1403.         return NULLCHAR;
  1404.     }
  1405.     while(fgets(buf,sizeof(buf),fp),!feof(fp)){
  1406.         buf[strlen(buf)-1] = '\0';      /* Nuke the newline */
  1407.         if(buf[0] == '#')
  1408.             continue;       /* Comment */
  1409.         if((cp = strchr(buf,' ')) == NULLCHAR)
  1410.             /* Bogus entry */
  1411.             continue;
  1412.         *cp++ = '\0';           /* Now points to user name */
  1413.         if(strcmp(host,buf) == 0)
  1414.             break;          /* Found host name */
  1415.     }
  1416.     if(feof(fp)){
  1417.         /* User name not found in file */
  1418.         fclose(fp);
  1419.         return NULLCHAR;
  1420.     }
  1421.     fclose(fp);
  1422.     /* Look for space after user field in file */
  1423.     if((cp1 = strchr(cp,' ')) == NULLCHAR)
  1424.         /* if not there then we'll prompt */
  1425.         ftp->password = NULLCHAR;
  1426.     else
  1427.         *cp1++ = '\0';          /* Now points to password */
  1428.         if(strcmp(cp,"*") == 0)
  1429.             cp1 = "anonymous";
  1430.         ftp->password = strdup(cp1);
  1431.     return strdup(cp);
  1432. }
  1433.  
  1434. int
  1435. dolcd(argc,argv,p)
  1436. int argc;
  1437. char *argv[];
  1438. void *p;
  1439. {
  1440.     register struct ftpcli *ftp;
  1441.  
  1442.     ftp = (struct ftpcli *)p;
  1443.     if(ftp == NULLFTP){
  1444.         tprintf(Notsess);
  1445.         return 1;
  1446.     }
  1447.  
  1448.     if(argc > 1){
  1449.             if (!dir_ok(argv[1],ftp->curdirs)) {
  1450.              
  1451.                  tprintf("Invalid Drive/Directory - %s\n",argv[1]);
  1452.                  return 1;
  1453.             }
  1454.            
  1455.     }
  1456.     tprintf("Local Directory - %s\n",ftp->curdirs->dir);
  1457.     
  1458.     return 0;
  1459. }
  1460.  
  1461.  
  1462. int
  1463. doldir(argc,argv,p)
  1464. int argc;
  1465. char *argv[];
  1466. void *p;
  1467. {
  1468.     register struct ftpcli *ftp;
  1469.     char ** margv;
  1470.  
  1471.     margv=(char **)callocw(2,sizeof(char*));
  1472.  
  1473.     ftp = (struct ftpcli *)p;
  1474.     if(ftp == NULLFTP){
  1475.         tprintf(Notsess);
  1476.         return 1;
  1477.     }
  1478.     
  1479.     tprintf("\n");
  1480.     margv[1]=strdup(make_dir_path(argc,argv[1],ftp->curdirs->dir));
  1481.     dodir(2,margv,p);
  1482.     free(margv[1]);
  1483.     free(margv);
  1484.     tprintf("\n");
  1485.     return 0;
  1486. }
  1487.  
  1488. int
  1489. dolmkdir(argc,argv,p)
  1490. int argc;
  1491. char *argv[];
  1492. void *p;
  1493. {
  1494.     register struct ftpcli *ftp;
  1495.     char *buf;
  1496.  
  1497.     ftp = (struct ftpcli *)p;
  1498.     if(ftp == NULLFTP){
  1499.         tprintf(Notsess);
  1500.         return 1;
  1501.     }
  1502.     undosify(argv[1]);
  1503.     buf=strdup(make_fname(ftp->curdirs->dir,argv[1]));
  1504. #ifdef UNIX
  1505.     if (mkdir(buf, 0777) == -1)
  1506. #else
  1507.     if (mkdir(buf) == -1)
  1508. #endif
  1509.         tprintf("Can't make %s: %s\n",buf,sys_errlist[errno]);
  1510.     else
  1511.         tprintf("Directory %s Created\n",buf);
  1512.     free(buf);
  1513.     return 0;
  1514. }                
  1515.  
  1516. #endif
  1517.  
  1518.